package org.example.aaaatest.jsonString;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class MultiThreadDownloader {
    private static final int BLOCK_SIZE = 10 * 1024 * 1024; // 10MB
    private static final int MAX_RETRY = 3;

    public static void main(String[] args) {
        try {
            new MultiThreadDownloader().downloadFile("http://example.com/file.zip", new File("downloaded.file"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void downloadFile(String fileUrl, File outputFile) throws Exception {
        int retryCount = 0;
        boolean success = false;

        while (retryCount < MAX_RETRY && !success) {
            try {
                long fileSize = getFileSize(fileUrl);
                int threadCount = (int) Math.ceil((double) fileSize / BLOCK_SIZE);

                ExecutorService executor = Executors.newFixedThreadPool(threadCount);
                List<Future<Boolean>> futures = new ArrayList<>();

                // 初始化文件
                try (RandomAccessFile raf = new RandomAccessFile(outputFile, "rw")) {
                    raf.setLength(fileSize);
                }

                // 创建下载任务
                for (int i = 0; i < threadCount; i++) {
                    long start = i * BLOCK_SIZE;
                    long end = Math.min(start + BLOCK_SIZE - 1, fileSize - 1);
                    futures.add(executor.submit(new DownloadTask(fileUrl, outputFile, start, end)));
                }

                executor.shutdown();

                // 检查结果
                boolean allSuccess = true;
                for (Future<Boolean> future : futures) {
                    if (!future.get()) allSuccess = false;
                }

                if (allSuccess && validateFile(outputFile)) {
                    success = true;
                    updateDbStatus("COMPLETED");
                } else {
                    throw new Exception("Download failed");
                }
            } catch (Exception e) {
                retryCount++;
                if (outputFile.exists()) outputFile.delete();
                if (retryCount >= MAX_RETRY) {
                    updateDbStatus("ERROR");
                    throw new Exception("Download failed after retries");
                }
            }
        }
    }

    private long getFileSize(String fileUrl) throws IOException {
        HttpURLConnection conn = (HttpURLConnection) new URL(fileUrl).openConnection();
        conn.setRequestProperty("Range", "bytes=0-0");
        int response = conn.getResponseCode();
        
        if (response == HttpURLConnection.HTTP_PARTIAL) {
            String contentRange = conn.getHeaderField("Content-Range");
            return Long.parseLong(contentRange.split("/")[1]);
        }
        throw new IOException("Can't get file size");
    }

    private boolean validateFile(File file) {
        // 实现CRC64校验逻辑
        return true; // 示例返回值
    }

    private void updateDbStatus(String status) {
        // 实现数据库更新逻辑
    }

    static class DownloadTask implements Callable<Boolean> {
        private final String url;
        private final File file;
        private final long start;
        private final long end;

        DownloadTask(String url, File file, long start, long end) {
            this.url = url;
            this.file = file;
            this.start = start;
            this.end = end;
        }

        @Override
        public Boolean call() {
            try {
                HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
                conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
                
                try (InputStream is = conn.getInputStream();
                     RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
                    
                    raf.seek(start);
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    
                    while ((bytesRead = is.read(buffer)) != -1) {
                        raf.write(buffer, 0, bytesRead);
                    }
                }
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    }
}